package cc.rengu.redp.bizimpl.upmp.service.impl;

import cc.rengu.redp.bizimpl.csmc.dao.RoleAcctInfoMapper;
import cc.rengu.redp.bizimpl.enums.TransLinkTypeEnum;
import cc.rengu.redp.bizimpl.igas.bean.*;
import cc.rengu.redp.bizimpl.igas.dao.PChannelCallCfgMapper;
import cc.rengu.redp.bizimpl.igas.domain.PChannelCallCfg;
import cc.rengu.redp.bizimpl.igas.domain.PSrcChannelInfo;
import cc.rengu.redp.bizimpl.upmp.bean.*;
import cc.rengu.redp.bizimpl.upmp.dao.BViewLinkCfgMapper;
import cc.rengu.redp.bizimpl.upmp.domain.BViewLinkCfg;
import cc.rengu.redp.bizimpl.upmp.service.IBViewLinkCfgService;
import cc.rengu.redp.bizimpl.upmp.vo.*;
import cc.rengu.redp.bizimpl.utils.DateUtils;
import cc.rengu.redp.common.exception.RedpException;
import cc.rengu.redp.common.utils.DateUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.text.DecimalFormat;
import java.time.LocalDateTime;
import java.util.*;

/**
 * @author System
 */
@DS("upmp")
@Service
public class BViewLinkCfgServiceImpl extends ServiceImpl<BViewLinkCfgMapper, BViewLinkCfg> implements IBViewLinkCfgService {
    private Logger logger = LoggerFactory.getLogger(BViewLinkCfgServiceImpl.class);

    private int xStart = 3000;
    private int yStart = 3000;
    private int xStep = 300;
    private int yStep = 50;

    @Autowired
    private PChannelCallCfgMapper pChannelCallCfgMapper;
    @Autowired
    private RoleAcctInfoMapper roleAcctInfoMapper;

    @Override
    public ServiceAndChannelInfoListQueryRespVO serviceAndChannelQuery(ServiceAndChannelInfoListQueryReqVO req) {

        logger.info("获取服务列表及交易渠道-请求报文:{}", JSON.toJSONString(req));
        List<ChannelServiceInfo> channelServiceInfos = pChannelCallCfgMapper.getChannelServiceInfoList(req.getInstId());
        List<LocalServiceInfo> localServiceInfos = pChannelCallCfgMapper.getLocalServiceInfoList(req.getInstId());
        List<PSrcChannelInfo> pSrcChannelInfos = pChannelCallCfgMapper.getSrcChannelInfoList(req.getInstId());
        Map<String, MsgSrcChannelInfo> msgSrcChannelInfos = Maps.newHashMap();
        for (PSrcChannelInfo srcChannelInfo : pSrcChannelInfos) {
            MsgSrcChannelInfo msgSrcChannelInfo = new MsgSrcChannelInfo();
            msgSrcChannelInfo.setMsgSrcId(srcChannelInfo.getSrcChannelId());
            msgSrcChannelInfo.setMsgSrcName(srcChannelInfo.getSrcChannelName());
            msgSrcChannelInfos.put(srcChannelInfo.getSrcChannelId(), msgSrcChannelInfo);
        }
        List<MsgSrcChannelInfo> msgSrcChannelInfoList = Lists.newArrayList();
        Iterator it = msgSrcChannelInfos.values().iterator();
        while (it.hasNext()) {
            MsgSrcChannelInfo info = (MsgSrcChannelInfo) it.next();
            List<TransChannelInfo> transChannelInfoList = Lists.newArrayList();
            for (PSrcChannelInfo srcChannelInfo : pSrcChannelInfos) {
                if (info.getMsgSrcId().equals(srcChannelInfo.getSrcChannelId())) {
                    TransChannelInfo transChannelInfo = new TransChannelInfo();
                    transChannelInfo.setTransChannelId(srcChannelInfo.getTransChannelId());
                    transChannelInfo.setTransChannelName(srcChannelInfo.getTransChannelName());
                    transChannelInfoList.add(transChannelInfo);
                }
/*                MsgSrcChannelInfo msgSrcChannelInfo = new MsgSrcChannelInfo();
                msgSrcChannelInfo.setMsgSrcId(srcChannelInfo.getSrcChannelId());
                msgSrcChannelInfo.setMsgSrcName(srcChannelInfo.getSrcChannelName());
                msgSrcChannelInfos.put(srcChannelInfo.getSrcChannelId(),msgSrcChannelInfo);*/
            }
            info.setTransChannelInfoList(transChannelInfoList);
            msgSrcChannelInfoList.add(info);
        }
//        pSrcChannelInfos.stream().distinct()
        ServiceAndChannelInfoListQueryRespVO resp = new ServiceAndChannelInfoListQueryRespVO();
        resp.setChannelServiceInfoList(channelServiceInfos);
        resp.setLocalServiceInfoList(localServiceInfos);
        resp.setMsgSrcChannelInfoList(msgSrcChannelInfoList);
        return resp;
    }

    @Override
    public TransChannelTxnInfoListQueryRespVO transChannelTxnQuery(TransChannelTxnInfoListQueryReqVO req) {
        logger.info("业务渠道交易类型查询-请求报文:{}", JSON.toJSONString(req));
        List<TransChannelTxnInfo> list = pChannelCallCfgMapper.getTransChannelTxnInfoList(req.getInstId(), req.getMsgSrcId(), req.getTransChannelId());
        TransChannelTxnInfoListQueryRespVO resp = new TransChannelTxnInfoListQueryRespVO();
        resp.setTransChannelTxnInfoList(list);
        return resp;
    }

    @Override
    public TransLinkCfgInfoQueryRespVO transLinkCfgInfoQuery(TransLinkCfgInfoQueryReqVO req) throws RedpException {

        logger.info("可视化链路配置查询-请求报文:{}", JSON.toJSONString(req));
        BViewLinkCfg obj = baseMapper.getTransLinkCfgInfoByUK(req.getInstId(),req.getViewType(), req.getMsgSrcId(), req.getTransChannelId(), req.getTxnNum(), req.getBizType());

        if (!ObjectUtils.isEmpty(obj) && !ObjectUtils.isEmpty(obj.getTxnLinkMsg())) {

            StringBuffer json = new StringBuffer(obj.getTxnLinkMsg());
            if (!StringUtils.isEmpty(obj.getTxnLinkMsg1())) {
                json.append(obj.getTxnLinkMsg1());
            }
            if (!StringUtils.isEmpty(obj.getTxnLinkMsg2())) {
                json.append(obj.getTxnLinkMsg2());
            }
            if (!StringUtils.isEmpty(obj.getTxnLinkMsg3())) {
                json.append(obj.getTxnLinkMsg3());
            }
            if (!StringUtils.isEmpty(obj.getTxnLinkMsg4())) {
                json.append(obj.getTxnLinkMsg4());
            }
            if (!StringUtils.isEmpty(obj.getTxnLinkMsg5())) {
                json.append(obj.getTxnLinkMsg5());
            }
            if (!StringUtils.isEmpty(obj.getTxnLinkMsg6())) {
                json.append(obj.getTxnLinkMsg6());
            }
            if (!StringUtils.isEmpty(obj.getTxnLinkMsg7())) {
                json.append(obj.getTxnLinkMsg7());
            }
            TransLinkCfg transLinkCfg = JSON.parseObject(json.toString(), TransLinkCfg.class);

            // 资金清算 解析json并赋值清算信息
            if ("01".equals(req.getViewType())) {
//                Map<String, RoleAcctInfo> roleAcctInfoMap = new HashMap<>();
//                List<RoleAcctInfo> roleAcctInfoList = roleAcctInfoMapper.findRoleAcctInfoListByUK(req.getInstId());
//                for (RoleAcctInfo roleAcctInfo : roleAcctInfoList) {
//                    roleAcctInfoMap.put(roleAcctInfo.getSettleAcctId(),roleAcctInfo);
//                }
                Map<String, NodeInfo> nodeInfoMap = new HashMap<>();
                for (NodeInfo nodeInfo : transLinkCfg.getNodeList()) {
                    nodeInfoMap.put(nodeInfo.getId(),nodeInfo);
                }

                for (TypeInfo typeInfo : transLinkCfg.getTypeList()) {
                    NodeInfo sourceNode = nodeInfoMap.get(typeInfo.getSourceId());
                    NodeInfo targetNode =nodeInfoMap.get( typeInfo.getTargetId());

                    String debitSettleAcctId = sourceNode.getSettleAcctId();
                    String debitRoleId = req.getInstId() + "" + sourceNode.getRoleId();

                    String creditSettleAcctId = targetNode.getSettleAcctId();
                    String creditRoleId = req.getInstId() + "" + targetNode.getRoleId();

                    String date = DateUtils.formatDate(new Date(), "yyyyMMdd");

                    
//                    List<SettleInstructionInfo> settleInstructionInfo = roleAcctInfoMapper.findSettleInstructionInfoListByUK(req.getInstId(), date, debitRoleId, debitSettleAcctId, creditRoleId, creditSettleAcctId);
                    List<SettleInstructionInfo> settleInstructionInfo = roleAcctInfoMapper.findSettleInstructionInfoListByUK(req.getInstId(), req.getSettleDate(), debitSettleAcctId, creditSettleAcctId);
                    int successCount = 0;
                    for (SettleInstructionInfo instructionInfo : settleInstructionInfo) {
                        if ("01".equals(instructionInfo.getAcctStatus())) {
                            successCount++;
                        }
                    }
                    typeInfo.setPercent(getPercent(successCount, settleInstructionInfo.size()));
                    typeInfo.setSettleInstructionList(settleInstructionInfo);
                }
            }
            TransLinkCfgInfoQueryRespVO resp = new TransLinkCfgInfoQueryRespVO();
            resp.setTransLinkCfgInfo(transLinkCfg);
            return resp;
        } else {
            if("00".equals(req.getViewType())) {

                TransChannelTxnInfo startTxn = pChannelCallCfgMapper.getTransChannelTxnInfoByUK(req.getInstId(), req.getMsgSrcId(), req.getTransChannelId(), req.getTxnNum(), req.getBizType());
                if (!ObjectUtils.isEmpty(startTxn)) {
                    List<NodeInfo> nodeList = Lists.newArrayList();
                    List<TypeInfo> typeList = Lists.newArrayList();
                    //创建起始节点
                    NodeInfo startNode = new NodeInfo();
                    startNode.setIcon("start");
                    startNode.setId("start-" + IdWorker.getIdStr());
                    startNode.setHeight("50");
                    startNode.setWidth("120");
                    startNode.setType("freedom");
                    startNode.setNodeName(startTxn.getTxnName());
                    startNode.setChannelTxnName(startTxn.getTxnName());
                    startNode.setX(String.valueOf(xStart));
                    startNode.setY(String.valueOf(yStart));
                    nodeList.add(startNode);
                    //寻找call_index='0000'的 通道服务调用配置
                    PChannelCallCfg reqCfg = new PChannelCallCfg();
                    //由于同一个交易链路的所有交易记录的 instId,msgSrcId,transChannelId,txnNum,bizType,bizScene,callChannelId,callChannelTxn 只有 callChannelTxn不一样，
                    // 这里不送 callChannelTxn 把数据库中已经配置的交易记录查询出来
                    reqCfg.setInstId(req.getInstId());
                    reqCfg.setMsgSrcId(req.getMsgSrcId());
                    reqCfg.setTransChannelId(req.getTransChannelId());
                    reqCfg.setTxnNum(req.getTxnNum());
                    reqCfg.setBizType(req.getBizType());
//            reqCfg.setBizScene(req.getBizScene());
//            reqCfg.setCallChannelId(req.getCallChannelId());
                    //获取数据库中的配置数据
                    List<PChannelCallCfg> list = pChannelCallCfgMapper.getPChannelCallCfgList(reqCfg);
                    if (ObjectUtils.isEmpty(list)) {
                        reqCfg.setTransChannelId("*");
                        list = pChannelCallCfgMapper.getPChannelCallCfgList(reqCfg);
                    }
                    int i = 1;
                    for (PChannelCallCfg cfg : list) {
                        if ("0000".equals(cfg.getCallIndex())) {
                            NodeInfo node = new NodeInfo();
                            BeanUtils.copyProperties(cfg, node);
                            node.setIcon("user");
                            node.setId("common-" + IdWorker.getIdStr());
                            node.setHeight("50");
                            node.setWidth("120");
                            node.setType("common");
                            node.setX(String.valueOf(xStart + xStep));
                            node.setY(String.valueOf(yStart + (i - 1) * yStep));
                            node.setNodeName(cfg.getCallChannelTxnName());
                            node.setChannelTxnName(cfg.getCallChannelTxnName());
                            node.setCallIndex(cfg.getCallIndex());
                            node.setCallChannelImpl(cfg.getCallChannelImpl());
                            node.setCallChannelImplDesc(cfg.getCallChannelImplDesc());
                            node.setChannelId(cfg.getCallChannelId());
                            node.setChannelTxnNum(cfg.getCallChannelTxn());
                            node.setInstId(cfg.getInstId());
                            node.setPrimaryKey(cfg.getPrimaryKey());
                            nodeList.add(node);

                            //场景线
                            TypeInfo typeScene = new TypeInfo();
                            typeScene.setSourceId(startNode.getId());
                            typeScene.setTargetId(node.getId());
                            typeScene.setBizScene(cfg.getBizScene());
                            typeScene.setBizSceneDesc(cfg.getBizSceneDesc());
                            typeScene.setType(TransLinkTypeEnum.CONN_SCENE.getType());
                            typeScene.setId(TransLinkTypeEnum.CONN_SCENE.getType() + "-" + IdWorker.getIdStr());
                            ClsInfo cls = new ClsInfo();
                            cls.setLinkColor("#2a2929");
                            cls.setLinkThickness("2");
                            cls.setLinkType("Flowchart");
                            typeScene.setCls(cls);
                            typeList.add(typeScene);

                            i++;
                            //查找调用成功后续节点
                            if (!StringUtils.isEmpty(cfg.getNextCallIndex())) {
                                i += analysisCfgToNode(list, nodeList, typeList, cfg, node, TransLinkTypeEnum.CONN_SUCCESS);
                            }
                            //查找调用超时后续节点
                            if (!StringUtils.isEmpty(cfg.getTimeoutCallIndex())) {
                                i += analysisCfgToNode(list, nodeList, typeList, cfg, node, TransLinkTypeEnum.CONN_OVERTIME);
                            }
                            //查找调用失败后续节点
                            if (!StringUtils.isEmpty(cfg.getFailCallIndex())) {
                                i += analysisCfgToNode(list, nodeList, typeList, cfg, node, TransLinkTypeEnum.CONN_FAIL);

                            }
                        }
                    }

                    TransLinkCfg transLinkCfg = new TransLinkCfg();
                    transLinkCfg.setNodeList(nodeList);
                    transLinkCfg.setTypeList(typeList);

                    AttrInfo attr = new AttrInfo();
                    attr.setId("flow-" + IdWorker.getIdStr());
                    transLinkCfg.setAttr(attr);
                    ConfigInfo config = new ConfigInfo();
                    config.setShowGrid("false");
                    config.setShowGridIcon("eye-invisible");
                    config.setShowGridText("显示网格");
                    transLinkCfg.setConfig(config);
                    transLinkCfg.setStatus("1");

                    TransLinkCfgInfoQueryRespVO resp = new TransLinkCfgInfoQueryRespVO();
                    resp.setTransLinkCfgInfo(transLinkCfg);

                    logger.info("可视化链路配置查询-应答报文:{}", JSON.toJSONString(resp));
                    return resp;
                } else {
                    throw new RedpException("没有查询到起始节点数据");
                }

            }else{
                throw new RedpException("没有查询到可视化链路配置数据");
            }
        }
    }

    @Override
//    @Transactional  跨数据库时加上这个注解会找不到另外一个库的表
    public void transLinkCfg(TransLinkCfgInfoCommitReqVO req) throws RedpException {
        logger.info("可视化链路配置提交-请求报文:{}", JSON.toJSONString(req));
        try {
            if("00".equals(req.getViewType())){
                savePChannelCallCfg(req);
            }
            saveBViewLinkCfg(req);
        }catch (Exception ex){
            ex.printStackTrace();
            logger.error("可视化链路配置提交出现异常",ex.getCause());
            throw new RedpException("可视化链路配置提交出现异常"+ex.getMessage());
        }
    }

    private String getPercent(int x, int total) {
        if (x == 0) {
            return "0.00%";
        }
        String result;//接受百分比的值
        double x_double = x * 1.0;
        double tempResult = x_double / total;
        DecimalFormat df1 = new DecimalFormat("0.00%");    //##.00%   百分比格式，后面不足2位的用0补齐
        result = df1.format(tempResult);
        return result;
    }

    @Override
    public RoleAcctInfoListQueryRespVO roleAcctQuery(RoleAcctInfoListQueryReqVO req) {
        logger.info("获取清分清算资金流转-获取角色账户列表-请求报文:{}", JSON.toJSONString(req));
        List<RoleAcctInfo> roleAcctInfoList = roleAcctInfoMapper.findRoleAcctInfoListByUK(req.getInstId());

        RoleAcctInfoListQueryRespVO resp = new RoleAcctInfoListQueryRespVO();
        resp.setRoleAcctInfoList(roleAcctInfoList);
        return resp;
    }

    private void savePChannelCallCfg(TransLinkCfgInfoCommitReqVO req) throws RedpException {
        TransLinkCfg transLinkCfg = req.getTransLinkCfgInfo();
        if (!ObjectUtils.isEmpty(transLinkCfg)) {
            List<NodeInfo> nodes = transLinkCfg.getNodeList();
            Map<String, NodeInfo> nodeMap = Maps.newHashMap();
            List<TypeInfo> types = transLinkCfg.getTypeList();
            if (!ObjectUtils.isEmpty(types)) {
                //待入库的 PChannelCallCfg
                List<PChannelCallCfg> cfgs = Lists.newArrayList();
                //获取场景线
                List<TypeInfo> typeSenceList = Lists.newArrayList();
                for (TypeInfo type : types) {
                    if (TransLinkTypeEnum.CONN_SCENE.getType().equals(type.getType())) {
                        typeSenceList.add(type);
                    }
                }

                if (!ObjectUtils.isEmpty(typeSenceList)) {
                    for (TypeInfo typeSence : typeSenceList) {

                        //根据场景线获取第一个节点
                        NodeInfo node1 = null;
                        for (NodeInfo node : nodes) {
                            nodeMap.put(node.getId(), node);
                            if (typeSence.getTargetId().equals(node.getId())) {
                                node1 = node;
                            }
                        }
                        PChannelCallCfg cfg = new PChannelCallCfg();
                        BeanUtils.copyProperties(node1, cfg);
                        cfg.setInstId(req.getInstId());
                        cfg.setMsgSrcId(req.getMsgSrcId());
                        cfg.setTransChannelId(req.getTransChannelId());
                        cfg.setTxnNum(req.getTxnNum());
                        cfg.setBizType(req.getBizType());
                        cfg.setBizScene(typeSence.getBizScene());
                        cfg.setBizSceneDesc(typeSence.getBizSceneDesc());
                        cfg.setCallChannelId(node1.getChannelId());
                        cfg.setCallChannelTxn(node1.getChannelTxnNum());
                        cfg.setCallChannelTxnName(node1.getChannelTxnName());
                        //源系统标识+交易渠道标识+内部交易码+业务细分+调用序号+业务场景+调用通道标识+通道交易码
                        String primaryKey = cfg.getMsgSrcId() + cfg.getTransChannelId() + cfg.getTxnNum()
                                + cfg.getBizType() + cfg.getCallIndex() + cfg.getBizScene() + cfg.getCallChannelId() + cfg.getCallChannelTxn();
                        cfg.setPrimaryKey(primaryKey);
                        NodeInfo node1NextSucc = null;
                        NodeInfo node1NextFail = null;
                        NodeInfo node1NextOver = null;
                        //                    List<PChannelCallCfg> cfgs = Lists.newArrayList();
                        if (!ObjectUtils.isEmpty(node1)) {
                            List<TypeInfo> node1NextTypes = Lists.newArrayList();//一个节点最多只能有三条输出线；一个节点最多只能有三条输入线，且三条输入线sourceid必须为同一个
                            for (TypeInfo type : types) {
                                if (type.getSourceId().equals(node1.getId())) {
                                    node1NextTypes.add(type);
                                    if (TransLinkTypeEnum.CONN_SUCCESS.getType().equals(type.getType())) {
                                        node1NextSucc = nodeMap.get(type.getTargetId());
                                    }
                                    if (TransLinkTypeEnum.CONN_FAIL.getType().equals(type.getType())) {
                                        node1NextFail = nodeMap.get(type.getTargetId());
                                    }
                                    if (TransLinkTypeEnum.CONN_OVERTIME.getType().equals(type.getType())) {
                                        node1NextOver = nodeMap.get(type.getTargetId());
                                    }
                                }
                            }
//                            if (node1NextTypes.size() > 3) {
//                                throw new RedpException("节点[id:" + node1.getId() + "]的输出线超过3条！");
//                            }
                            if (!ObjectUtils.isEmpty(node1NextSucc)) {
                                cfg.setNextCallIndex(node1NextSucc.getCallIndex());
                            }
                            if (!ObjectUtils.isEmpty(node1NextFail)) {
                                cfg.setFailCallIndex(node1NextFail.getCallIndex());
                            }
                            if (!ObjectUtils.isEmpty(node1NextOver)) {
                                cfg.setTimeoutCallIndex(node1NextOver.getCallIndex());
                            }
                            cfg.setCreateTime(DateUtil.formatFullTime(LocalDateTime.now(), DateUtil.FULL_TIME_WITH_MILL_SPLIT_PATTERN));
                            cfgs.add(cfg);
                            //继续检查下级节点
                            if (!ObjectUtils.isEmpty(node1NextSucc)) {
                                analysisNodeToCfg(typeSence, cfg, nodeMap, types, cfgs, node1NextSucc);
                            }
                            if (!ObjectUtils.isEmpty(node1NextFail)) {
                                analysisNodeToCfg(typeSence, cfg, nodeMap, types, cfgs, node1NextFail);
                            }
                            if (!ObjectUtils.isEmpty(node1NextOver)) {
                                analysisNodeToCfg(typeSence, cfg, nodeMap, types, cfgs, node1NextOver);
                            }
                        }

                    }
                } else {
                    throw new RedpException("没有获取到场景线！");
                }
                if (!ObjectUtils.isEmpty(cfgs)) {
                    PChannelCallCfg reqCfg = new PChannelCallCfg();
                    //由于同一个交易链路的所有交易记录的 instId,msgSrcId,transChannelId,txnNum,bizType,bizScene,callChannelId,callChannelTxn 只有 bizScene,callChannelId,callChannelTxn不一样，
                    // 这里不送 bizScene,callChannelId,callChannelTxn 把数据库中已经配置的交易记录查询出来
                    reqCfg.setInstId(cfgs.get(0).getInstId());
                    reqCfg.setMsgSrcId(cfgs.get(0).getMsgSrcId());
                    reqCfg.setTransChannelId(cfgs.get(0).getTransChannelId());
                    reqCfg.setTxnNum(cfgs.get(0).getTxnNum());
                    reqCfg.setBizType(cfgs.get(0).getBizType());
//                    reqCfg.setBizScene(cfgs.get(0).getBizScene());
//                    reqCfg.setCallChannelId(cfgs.get(0).getCallChannelId());

                    //获取数据库中的配置数据
                    List<PChannelCallCfg> list = pChannelCallCfgMapper.getPChannelCallCfgList(reqCfg);
                    if (!ObjectUtils.isEmpty(list)) {//如果数据库中原来存在数据，则比较生成insert、update、delete的list,然后分别执行入库操作
                        List<PChannelCallCfg> insertList = Lists.newArrayList();
                        List<PChannelCallCfg> updateList = Lists.newArrayList();
                        List<PChannelCallCfg> deleteList = Lists.newArrayList();

                        //生成insert、update的list
                        for (PChannelCallCfg cfg : cfgs) {
                            boolean newData = true;
                            for (PChannelCallCfg cfgdb : list) {
                                if (cfg.getInstId().equals(cfgdb.getInstId())
                                        && cfg.getPrimaryKey().equals(cfgdb.getPrimaryKey())) {
                                    cfg.setCreateTime(cfgdb.getCreateTime());
                                    cfg.setUpdateTime(DateUtil.formatFullTime(LocalDateTime.now(), DateUtil.FULL_TIME_WITH_MILL_SPLIT_PATTERN));
                                    updateList.add(cfg);
                                    newData = false;
                                }
                            }
                            if (newData) {
                                insertList.add(cfg);
                            }
                        }

                        //生成delete的list
                        for (PChannelCallCfg cfgdb : list) {
                            boolean delete = true;
                            for (PChannelCallCfg cfg : cfgs) {
                                if (cfg.getInstId().equals(cfgdb.getInstId())
                                        && cfg.getPrimaryKey().equals(cfgdb.getPrimaryKey())) {
                                    delete = false;
                                }
                            }
                            if (delete) {
                                deleteList.add(cfgdb);
                            }
                        }

                        //删除入库
                        if (!ObjectUtils.isEmpty(deleteList)) {
                            for (PChannelCallCfg cfg : deleteList) {
                                pChannelCallCfgMapper.delPChannelCallCfgByUK(cfg);
                            }
                        }

                        //新增入库
                        if (!ObjectUtils.isEmpty(insertList)) {
                            for (PChannelCallCfg cfg : insertList) {
                                pChannelCallCfgMapper.addPChannelCallCfg(cfg);
                            }
                        }

                        //修改入库
                        if (!ObjectUtils.isEmpty(updateList)) {
                            for (PChannelCallCfg cfg : updateList) {
                                pChannelCallCfgMapper.updPChannelCallCfg(cfg);
                            }
                        }
                    } else {//如果数据库中原来不存在数据则直接执行insert
                        //新增入库
                        if (!ObjectUtils.isEmpty(cfgs)) {
                            for (PChannelCallCfg cfg : cfgs) {
                                pChannelCallCfgMapper.addPChannelCallCfg(cfg);
                            }
                        }
                    }
                } else {
                    throw new RedpException("没有获取到通道服务调用配置！");
                }

            } else {
                throw new RedpException("没有获取到链接线！");
            }
        } else {
            throw new RedpException("上送配置信息不能为空！");
        }
    }

    private void saveBViewLinkCfg(TransLinkCfgInfoCommitReqVO req) throws Exception {
        TransLinkCfg transLinkCfg = req.getTransLinkCfgInfo();
        if (!ObjectUtils.isEmpty(transLinkCfg)) {
            //保存 TransLinkCfg
            String bizData = JSON.toJSONString(transLinkCfg);
            if (bizData.getBytes("UTF-8").length > 24000) {
                logger.error("交易链路配置提交数据长度为" + bizData.length() + "，超过24000");
                throw new RedpException("交易链路配置提交数据长度为" + bizData.length() + "，超过24000，请联系管理员！");
            }
            String bizData0 = "";
            String bizData1 = "";
            String bizData2 = "";
            String bizData3 = "";
            String bizData4 = "";
            String bizData5 = "";
            String bizData6 = "";
            String bizData7 = "";

            if (bizData.length() > 3000) {
                bizData0 = bizData.substring(0, 3000);
                bizData1 = bizData.substring(3000);
            } else {
                bizData0 = bizData;
            }
            if (bizData1.length() > 3000) {
                bizData2 = bizData1.substring(3000);
                bizData1 = bizData1.substring(0, 3000);
            }
            if (bizData2.length() > 3000) {
                bizData3 = bizData2.substring(3000);
                bizData2 = bizData2.substring(0, 3000);
            }
            if (bizData3.length() > 3000) {
                bizData4 = bizData3.substring(3000);
                bizData3 = bizData3.substring(0, 3000);
            }
            if (bizData4.length() > 3000) {
                bizData5 = bizData4.substring(3000);
                bizData4 = bizData4.substring(0, 3000);
            }
            if (bizData5.length() > 3000) {
                bizData6 = bizData5.substring(3000);
                bizData5 = bizData5.substring(0, 3000);
            }
            if (bizData6.length() > 3000) {
                bizData7 = bizData7.substring(3000);
                bizData7 = bizData7.substring(0, 3000);
            }
/*
            if (bizData.getBytes("UTF-8").length > 4000) {
                bizData0 = subStringByByteLen(bizData,3999);//bizData.substring(0, 3999);
                bizData1 = bizData.replace(bizData0,"");
            } else {
                bizData0 = bizData;
            }
            if (bizData1.getBytes("UTF-8").length > 4000) {
                String dataTmp = subStringByByteLen(bizData1,3999);
                bizData2 = bizData1.replace(dataTmp,"");
                bizData1 = dataTmp;
            }
            if (bizData2.getBytes("UTF-8").length > 4000) {
                String dataTmp = subStringByByteLen(bizData2,3999);
                bizData3 = bizData2.replace(dataTmp,"");
                bizData2 = dataTmp;
            }
            if (bizData3.getBytes("UTF-8").length > 4000) {
                String dataTmp = subStringByByteLen(bizData3,3999);
                bizData4 = bizData3.replace(dataTmp,"");
                bizData3 = dataTmp;
            }
            if (bizData4.length() > 4000) {
                String dataTmp = subStringByByteLen(bizData4,3999);
                bizData5 = bizData4.replace(dataTmp,"");
                bizData4 = dataTmp;
            }*/

            BViewLinkCfg cfgDb = baseMapper.getTransLinkCfgInfoByUK(req.getInstId(),req.getViewType(), req.getMsgSrcId(), req.getTransChannelId(), req.getTxnNum(), req.getBizType());
            if (ObjectUtils.isEmpty(cfgDb)) {
                cfgDb = new BViewLinkCfg();
                cfgDb.setInstId(req.getInstId());
                cfgDb.setMsgSrcId(req.getMsgSrcId());
                cfgDb.setTransChannelId(req.getTransChannelId());
                cfgDb.setTxnNum(req.getTxnNum());
                cfgDb.setBizType(req.getBizType());
                cfgDb.setViewType(req.getViewType());
                cfgDb.setCreateTime(DateUtil.formatFullTime(LocalDateTime.now(), DateUtil.FULL_TIME_WITH_MILL_SPLIT_PATTERN));

//                if (bizData0.length() > 0) {
                    cfgDb.setTxnLinkMsg(bizData0);
//                }
//                if (bizData1.length() > 0) {
                    cfgDb.setTxnLinkMsg1(bizData1);
//                }
//                if (bizData2.length() > 0) {
                    cfgDb.setTxnLinkMsg2(bizData2);
//                }
//                if (bizData3.length() > 0) {
                    cfgDb.setTxnLinkMsg3(bizData3);
//                }
//                if (bizData4.length() > 0) {
                    cfgDb.setTxnLinkMsg4(bizData4);
//                }
//                if (bizData5.length() > 0) {
                    cfgDb.setTxnLinkMsg5(bizData5);
//                }
//                if (bizData6.length() > 0) {
                    cfgDb.setTxnLinkMsg6(bizData6);
//                }
//                if (bizData7.length() > 0) {
                    cfgDb.setTxnLinkMsg7(bizData7);
//                }
                baseMapper.addBViewLinkCfg(cfgDb);
            } else {
                cfgDb.setUpdateTime(DateUtil.formatFullTime(LocalDateTime.now(), DateUtil.FULL_TIME_WITH_MILL_SPLIT_PATTERN));
//                if (bizData0.length() > 0) {
                    cfgDb.setTxnLinkMsg(bizData0);
//                }
//                if (bizData1.length() > 0) {
                    cfgDb.setTxnLinkMsg1(bizData1);
//                }
//                if (bizData2.length() > 0) {
                    cfgDb.setTxnLinkMsg2(bizData2);
//                }
//                if (bizData3.length() > 0) {
                    cfgDb.setTxnLinkMsg3(bizData3);
//                }
//                if (bizData4.length() > 0) {
                    cfgDb.setTxnLinkMsg4(bizData4);
//                }
//                if (bizData5.length() > 0) {
                    cfgDb.setTxnLinkMsg5(bizData5);
//                }
//                if (bizData6.length() > 0) {
                    cfgDb.setTxnLinkMsg6(bizData6);
//                }
//                if (bizData7.length() > 0) {
                    cfgDb.setTxnLinkMsg7(bizData7);
//                }
                baseMapper.updBViewLinkCfg(cfgDb);
            }
        } else {
            throw new RedpException("上送配置信息不能为空！");
        }
    }

    /**
     * 解析场景线及第一个有效节点以后的节点
     *
     * @param typeSence  场景线
     * @param cfgPrev    上一级节点转换之后的待入库对象
     * @param nodeMap    节点map
     * @param origTypes  原始的TypeInfo对象集合
     * @param targetCfgs 入库对象集合解析后
     * @param sourceNode 当前待解析节点
     * @throws RedpException
     */
    private void analysisNodeToCfg(TypeInfo typeSence, PChannelCallCfg cfgPrev, Map<String, NodeInfo> nodeMap, List<TypeInfo> origTypes, List<PChannelCallCfg> targetCfgs, NodeInfo sourceNode) throws RedpException {

        //1、检查入线是否只有3条,且3条输入线的sourceId为同一个
        List<TypeInfo> nodePrevTypes = Lists.newArrayList();//一个节点最多只能有三条出线；一个节点最多只能有三条入线，且三条入线sourceid必须为同一个
        String sourceId = "";
        for (TypeInfo type : origTypes) {
            if (sourceNode.getId().equals(type.getTargetId())) {
                nodePrevTypes.add(type);
                if ("".equals(sourceId)) {
                    sourceId = type.getSourceId();
                } else {
                    /*if (!sourceId.equals(type.getSourceId())) {
                        throw new RedpException("节点[id:" + sourceNode.getId() + "]的输入线来源ID不一致！");
                    }*/
                }
            }
        }
//        if (nodePrevTypes.size() > 3) {
//            throw new RedpException("节点[id:" + sourceNode.getId() + "]的输入线超过3条！");
//        }

        //2、检查出线是否只有3条
        NodeInfo nodeNextSucc = null;
        NodeInfo nodeNextFail = null;
        NodeInfo nodeNextOver = null;
        List<TypeInfo> nodeNextTypes = Lists.newArrayList();//一个节点最多只能有三条出线；一个节点最多只能有三条入线，且三条入线sourceid必须为同一个
        for (TypeInfo type : origTypes) {
            if (type.getSourceId().equals(sourceNode.getId())) {
                nodeNextTypes.add(type);
                if (TransLinkTypeEnum.CONN_SUCCESS.getType().equals(type.getType())) {
                    nodeNextSucc = nodeMap.get(type.getTargetId());
                }
                if (TransLinkTypeEnum.CONN_FAIL.getType().equals(type.getType())) {
                    nodeNextFail = nodeMap.get(type.getTargetId());
                }
                if (TransLinkTypeEnum.CONN_OVERTIME.getType().equals(type.getType())) {
                    nodeNextOver = nodeMap.get(type.getTargetId());
                }
            }
        }
//        if (nodePrevTypes.size() > 3) {
//            throw new RedpException("节点[id:" + sourceNode.getId() + "]的输出线超过3条！");
//        }
        PChannelCallCfg cfg = new PChannelCallCfg();
        BeanUtils.copyProperties(sourceNode, cfg);
        cfg.setInstId(cfgPrev.getInstId());
        cfg.setMsgSrcId(cfgPrev.getMsgSrcId());
        cfg.setTransChannelId(cfgPrev.getTransChannelId());
        cfg.setTxnNum(cfgPrev.getTxnNum());
        cfg.setBizType(cfgPrev.getBizType());
        cfg.setBizScene(typeSence.getBizScene());
        cfg.setBizSceneDesc(typeSence.getBizSceneDesc());
        cfg.setCallChannelId(sourceNode.getChannelId());
        cfg.setCallChannelTxn(sourceNode.getChannelTxnNum());
        cfg.setCallChannelTxnName(sourceNode.getChannelTxnName());
        //源系统标识+交易渠道标识+内部交易码+业务细分+调用序号+业务场景+调用通道标识+通道交易码
        String primaryKey = cfg.getMsgSrcId() + cfg.getTransChannelId() + cfg.getTxnNum()
                + cfg.getBizType() + cfg.getCallIndex() + cfg.getBizScene() + cfg.getCallChannelId() + cfg.getCallChannelTxn();
        cfg.setPrimaryKey(primaryKey);
        if (!ObjectUtils.isEmpty(nodeNextSucc)) {
            cfg.setNextCallIndex(nodeNextSucc.getCallIndex());
        }
        if (!ObjectUtils.isEmpty(nodeNextFail)) {
            cfg.setFailCallIndex(nodeNextFail.getCallIndex());
        }
        if (!ObjectUtils.isEmpty(nodeNextOver)) {
            cfg.setTimeoutCallIndex(nodeNextOver.getCallIndex());
        }
        cfg.setCreateTime(DateUtil.formatFullTime(LocalDateTime.now(), DateUtil.FULL_TIME_WITH_MILL_SPLIT_PATTERN));
        //判断 targetCfgs 中是否已经存在相同主键的记录，如果已经存在则不再加入，否则加入
        boolean existCfg = false;
        for(PChannelCallCfg targetCfg:targetCfgs){
            if(cfg.getInstId().equals(targetCfg.getInstId())
                &&cfg.getPrimaryKey().equals(targetCfg.getPrimaryKey())){
                existCfg = true;
            }
        }
        if(!existCfg){
            targetCfgs.add(cfg);
        }
        //继续递归下级节点
        if (!ObjectUtils.isEmpty(nodeNextSucc)) {
            analysisNodeToCfg(typeSence, cfg, nodeMap, origTypes, targetCfgs, nodeNextSucc);
        }
        if (!ObjectUtils.isEmpty(nodeNextFail)) {
            analysisNodeToCfg(typeSence, cfg, nodeMap, origTypes, targetCfgs, nodeNextFail);
        }
        if (!ObjectUtils.isEmpty(nodeNextOver)) {
            analysisNodeToCfg(typeSence, cfg, nodeMap, origTypes, targetCfgs, nodeNextOver);
        }
    }

    public int analysisCfgToNode(List<PChannelCallCfg> list, List<NodeInfo> nodeList, List<TypeInfo> typeList, PChannelCallCfg cfg, NodeInfo node, TransLinkTypeEnum linkType) {
        int step=0;
        for (int i = 0; i < list.size(); i++) {
            PChannelCallCfg sonCfg = list.get(i);
            if (matchCfg(cfg,sonCfg,linkType)) {
                //先判断 nodeList中是否已经存在 这样的node,如果存在则只增加一条链接线，不增加node；如果不存在则增加连接线也增加node
                boolean exist = false;
                NodeInfo nextNode = null;
                for (NodeInfo nodeInfo : nodeList) {
                    if (sonCfg.getInstId().equals(nodeInfo.getInstId())
                            && sonCfg.getPrimaryKey().equals(nodeInfo.getPrimaryKey())) {
                        exist=true;
                        nextNode = nodeInfo;
                        break;
                    }
                }
                if(exist){

                    //判断连接线是否已经存在
                    boolean existType = false;
                    for(TypeInfo typeInfo:typeList){
                        if(node.getId().equals(typeInfo.getSourceId())
                        &&nextNode.getId().equals(typeInfo.getTargetId())
                        &&cfg.getBizScene().equals(typeInfo.getBizScene())
                        &&linkType.getType().equals(typeInfo.getType())){
                            existType=true;
                        }
                    }
                    if(!existType){
                        //连接线
                        TypeInfo typeCommon = new TypeInfo();
                        typeCommon.setSourceId(node.getId());
                        typeCommon.setTargetId(nextNode.getId());
                        typeCommon.setBizScene(cfg.getBizScene());
//                        typeCommon.setBizSceneDesc(cfg.getBizSceneDesc());
                        typeCommon.setType(linkType.getType());
                        typeCommon.setId(linkType.getType() + "-" + IdWorker.getIdStr());
                        ClsInfo cls = new ClsInfo();
                        if(TransLinkTypeEnum.CONN_SUCCESS.getType().equals(linkType.getType())){
                            //  成功  	#9400D3  ，失败  #b80000,超时  #47D1FF
                            cls.setLinkColor("#9400D3");
                        }else if(TransLinkTypeEnum.CONN_OVERTIME.getType().equals(linkType.getType())){
                            cls.setLinkColor("#47D1FF");
                        }else if(TransLinkTypeEnum.CONN_FAIL.getType().equals(linkType.getType())){
                            cls.setLinkColor("#b80000");
                        }else{
                            cls.setLinkColor("#2a2929");
                        }
                        cls.setLinkThickness("2");
                        cls.setLinkType("Flowchart");
                        typeCommon.setCls(cls);
                        typeList.add(typeCommon);
                    }
                }else{

                    nextNode = new NodeInfo();
                    BeanUtils.copyProperties(sonCfg, nextNode);
                    nextNode.setIcon("user");
                    nextNode.setId("common-" + IdWorker.getIdStr());
                    nextNode.setHeight("50");
                    nextNode.setWidth("120");
                    nextNode.setType("common");
                    nextNode.setX(String.valueOf(Integer.valueOf(node.getX())+  xStep));
                    nextNode.setY(String.valueOf(Integer.valueOf(node.getY()) +  yStep));
                    nextNode.setNodeName(sonCfg.getCallChannelTxnName());
                    nextNode.setChannelTxnName(sonCfg.getCallChannelTxnName());
                    nextNode.setCallIndex(sonCfg.getCallIndex());
                    nextNode.setCallChannelImpl(sonCfg.getCallChannelImpl());
                    nextNode.setCallChannelImplDesc(sonCfg.getCallChannelImplDesc());
                    nextNode.setChannelId(sonCfg.getCallChannelId());
                    nextNode.setChannelTxnNum(sonCfg.getCallChannelTxn());
                    nextNode.setInstId(sonCfg.getInstId());
                    nextNode.setPrimaryKey(sonCfg.getPrimaryKey());
                    nodeList.add(nextNode);

                    //连接线
                    TypeInfo typeCommon = new TypeInfo();
                    typeCommon.setSourceId(node.getId());
                    typeCommon.setTargetId(nextNode.getId());
                    typeCommon.setBizScene(cfg.getBizScene());
//                    typeCommon.setBizSceneDesc(cfg.getBizSceneDesc());
                    typeCommon.setType(linkType.getType());
                    typeCommon.setId(linkType.getType() + "-" + IdWorker.getIdStr());
                    ClsInfo cls = new ClsInfo();
                    if(TransLinkTypeEnum.CONN_SUCCESS.getType().equals(linkType.getType())){
                        //  成功  	#9400D3  ，失败  #b80000,超时  #47D1FF
                        cls.setLinkColor("#9400D3");
                    }else if(TransLinkTypeEnum.CONN_OVERTIME.getType().equals(linkType.getType())){
                        cls.setLinkColor("#47D1FF");
                    }else if(TransLinkTypeEnum.CONN_FAIL.getType().equals(linkType.getType())){
                        cls.setLinkColor("#b80000");
                    }else{
                        cls.setLinkColor("#2a2929");
                    }
                    cls.setLinkThickness("2");
                    cls.setLinkType("Flowchart");
                    typeCommon.setCls(cls);
                    typeList.add(typeCommon);
                    step++;
                }

                //查找调用成功后续节点
                if (!StringUtils.isEmpty(sonCfg.getNextCallIndex())) {
                    step+=analysisCfgToNode(list, nodeList, typeList, sonCfg, nextNode, TransLinkTypeEnum.CONN_SUCCESS);
                }
                //查找调用超时后续节点
                if (!StringUtils.isEmpty(sonCfg.getTimeoutCallIndex())) {
                    step+=analysisCfgToNode(list, nodeList, typeList, sonCfg, nextNode, TransLinkTypeEnum.CONN_OVERTIME);
                }
                //查找调用失败后续节点
                if (!StringUtils.isEmpty(sonCfg.getFailCallIndex())) {
                    step+=analysisCfgToNode(list, nodeList, typeList, sonCfg, nextNode, TransLinkTypeEnum.CONN_FAIL);
                }
                break;
            }

        }
        return step;
    }

    private boolean matchCfg(PChannelCallCfg cfg,PChannelCallCfg sonCfg,TransLinkTypeEnum linkType){
        if(TransLinkTypeEnum.CONN_SUCCESS.getType().equals(linkType.getType())){
            if(cfg.getInstId().equals(sonCfg.getInstId())
                    && cfg.getMsgSrcId().equals(sonCfg.getMsgSrcId())
                    && cfg.getTransChannelId().equals(sonCfg.getTransChannelId())
                    && cfg.getTxnNum().equals(sonCfg.getTxnNum())
                    && cfg.getBizType().equals(sonCfg.getBizType())
                    && cfg.getBizScene().equals(sonCfg.getBizScene())
                    && cfg.getNextCallIndex().equals(sonCfg.getCallIndex())){
                return true;
            }

        }else if(TransLinkTypeEnum.CONN_OVERTIME.getType().equals(linkType.getType())){

            if(cfg.getInstId().equals(sonCfg.getInstId())
                    && cfg.getMsgSrcId().equals(sonCfg.getMsgSrcId())
                    && cfg.getTransChannelId().equals(sonCfg.getTransChannelId())
                    && cfg.getTxnNum().equals(sonCfg.getTxnNum())
                    && cfg.getBizType().equals(sonCfg.getBizType())
                    && cfg.getBizScene().equals(sonCfg.getBizScene())
                    && cfg.getTimeoutCallIndex().equals(sonCfg.getCallIndex())){
                return true;
            }
        }else if(TransLinkTypeEnum.CONN_FAIL.getType().equals(linkType.getType())){

            if(cfg.getInstId().equals(sonCfg.getInstId())
                    && cfg.getMsgSrcId().equals(sonCfg.getMsgSrcId())
                    && cfg.getTransChannelId().equals(sonCfg.getTransChannelId())
                    && cfg.getTxnNum().equals(sonCfg.getTxnNum())
                    && cfg.getBizType().equals(sonCfg.getBizType())
                    && cfg.getBizScene().equals(sonCfg.getBizScene())
                    && cfg.getFailCallIndex().equals(sonCfg.getCallIndex())){
                return true;
            }
        }
        return  false;
    }


    /**
     * 判断传进来的字符串，是否
     * 大于指定的字节，如果大于递归调用
     * 直到小于指定字节数 ，一定要指定字符编码，因为各个系统字符编码都不一样，字节数也不一样
     * @param s 原始字符串
     *
     * @param num 传进来指定字节数,截取长度
     *
     * @return String 截取后的字符串
     */
    /*public  String subStringByByteLen(String s,int num)throws Exception{
        int changdu = s.getBytes("UTF-8").length;
        if(changdu > num){
            s = s.substring(0, s.length() - 1);
            s = subStringByByteLen(s,num);
        }
        return s;
    }*/
}
